﻿using BZ.Core;
using NDK.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using TwinCAT.Ads;

namespace NDK.Motion.Card
{
    /// <summary>
    /// PLC Type  UnmanagedType 
    /// LREAL     R8             double
    /// BOOL      I1             bool
    /// UDINT     U4             UInt32
    /// BYTE      I1             Byte
    /// 
    /// </summary>
    [StructLayout(LayoutKind.Sequential, Pack = 8)]//注意TC2的话改为Pack = 1.
    [Serializable]
    public struct ST_ManualMoitonCmd
    {
        [MarshalAs(UnmanagedType.I1)]
        public bool bEnable;//上使能
        [MarshalAs(UnmanagedType.I1)]
        public bool bPosLim;//允许正转
        [MarshalAs(UnmanagedType.I1)]
        public bool bNegLim;//允许反转
        [MarshalAs(UnmanagedType.R8)]
        public double rOverRide;//速度百分比
        [MarshalAs(UnmanagedType.I1)]
        public bool bRefCam;

        [MarshalAs(UnmanagedType.I1)]
        public bool bStop;//轴停止
        [MarshalAs(UnmanagedType.I1)]
        public bool bHalt;//轴停止
        [MarshalAs(UnmanagedType.I1)]
        public bool bReset;//报警复位

        //Home
        [MarshalAs(UnmanagedType.I1)]
        public bool bHome;//轴回零
        [MarshalAs(UnmanagedType.R8)]
        public double rHomeShift;//回零点偏移
        [MarshalAs(UnmanagedType.I1)]
        public byte bHomeSearchDir;//回零搜索方向 1正方向, 3负方向,    mcSwitchPositive    := 5,    mcSwitchNegative    := 7
        [MarshalAs(UnmanagedType.I1)]
        public byte bHomeMode;//0:找原点；1：找限位



        //SetPostion
        [MarshalAs(UnmanagedType.I1)]
        public bool bSetPostion;//设定轴位置
        [MarshalAs(UnmanagedType.R8)]
        public double rSetPositon;//把当前位置，设定为该位置

        //JOG
        [MarshalAs(UnmanagedType.I1)]
        public bool bJogP;//正向点动
        [MarshalAs(UnmanagedType.I1)]
        public bool bJogN;//负向点动

        //Move Endless(Move Velocity)
        [MarshalAs(UnmanagedType.I1)]
        public bool bMoveVeloStart;//触发匀速运动
        [MarshalAs(UnmanagedType.R8)]
        public double rSetVelo;//设定匀速运动的速度
        [MarshalAs(UnmanagedType.I1)]
        public byte bDir;//运动方向（/*MC_Positive_Direction = 1, MC_Shortest_Way=2,MC_Negative_Direction=3,  MC_Current_Direction=4

        //Move ABS
        [MarshalAs(UnmanagedType.I1)]
        public bool bMoveAbsStart;//触发绝对运动
        [MarshalAs(UnmanagedType.R8)]
        public double rMoveAbsSetPos;//设定绝对运动的位置

        //Move relative
        [MarshalAs(UnmanagedType.I1)]
        public bool bMoveRelativeStart;//触发相对运动
        [MarshalAs(UnmanagedType.R8)]
        public double rMoveRelativeSetPos;//设定相对运动的位置

        [MarshalAs(UnmanagedType.R8)]
        public double rAcc;//加速度
        [MarshalAs(UnmanagedType.R8)]
        public double rDec;//减速度
    }

    [StructLayout(LayoutKind.Sequential, Pack = 8)]//注意TC2的话改为Pack = 1.
    [Serializable]
    public struct ST_fbMotionSatus
    {
        [MarshalAs(UnmanagedType.I1)]
        public bool bINP;//
        [MarshalAs(UnmanagedType.I1)]
        public bool bEMG;//
        [MarshalAs(UnmanagedType.I1)]
        public bool bALM;//
        [MarshalAs(UnmanagedType.I1)]
        public bool bServoStatus;//轴使能状态
        [MarshalAs(UnmanagedType.R8)]
        public double rActPos;//轴当前位置
        [MarshalAs(UnmanagedType.R8)]
        public double rErrPos;//轴跟随误差

        [MarshalAs(UnmanagedType.I1)]
        public bool bHoming;//
        [MarshalAs(UnmanagedType.I1)]
        public bool bHomed;//
        [MarshalAs(UnmanagedType.I1)]
        public bool bHomeErr;//
        [MarshalAs(UnmanagedType.I1)]
        public bool bHomeFail;//

        [MarshalAs(UnmanagedType.I1)]
        public bool bMoving;//

        [MarshalAs(UnmanagedType.I1)]
        public bool bPEL;//
        [MarshalAs(UnmanagedType.I1)]
        public bool bMEL;//
        [MarshalAs(UnmanagedType.I1)]
        public bool bORG;


    }
    [StructLayout(LayoutKind.Sequential, Pack = 8)]
    [Serializable]
    public struct ST_Motion
    {
        //[MarshalAs(UnmanagedType.BStr)]
        //public string sAxisName;
        [MarshalAs(UnmanagedType.Struct)]
        public ST_ManualMoitonCmd MoitonCmd;
        [MarshalAs(UnmanagedType.Struct)]
        public ST_fbMotionSatus MotionStatus;
    }
    [Serializable]
    public struct Axes
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public ST_Motion[] Motion;
    }
    [Serializable]
    public struct Outputs
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)]
        public byte[] Output;
    }
    [Serializable]
    public class Beckhoff : IMotionCard, IOCard
    {
        #region fileds/properties
        [NonSerialized]
        public TcAdsClient _client = null;
        private string _cardName;
        private int _cardID;
        private int _totalAxis;
        private int _inputCount;
        private int _outputCount;
        private string _adlinkCardType;
        private int _startAxisID;
        [NonSerialized]
        private bool _initialized;
        public string CardName
        {
            get
            {
                return _cardName;
            }

            set
            {
                _cardName = value;
            }
        }

        public int CardID
        {
            get
            {
                return _cardID;
            }

            set
            {
                _cardID = value;
            }
        }

        public int TotalAxis
        {
            get
            {
                return _totalAxis;
            }

            set
            {
                _totalAxis = value;
            }
        }

        public int InputCount
        {
            get
            {
                return _inputCount;
            }

            set
            {
                _inputCount = value;
            }
        }

        public int OutputCount
        {
            get
            {
                return _outputCount;
            }

            set
            {
                _outputCount = value;
            }
        }

        public string CardType
        {
            get
            {
                return _adlinkCardType;
            }

            set
            {
                _adlinkCardType = value;
            }
        }

        public int StartAxisID
        {
            get
            {
                return _startAxisID;
            }

            set
            {
                _startAxisID = value;
            }
        }

        public bool Initialized
        {
            get
            {
                return _initialized;
            }

            set
            {
                _initialized = value;
            }
        }

        public const int ON = 1;
        public const int OFF = 0;



        #endregion

        private int _AxisHandle = 0;
        private int _notificationAxisHandle = 0;
        private Axes _Axes = new Axes();
        bool[] InputArray = null;
        bool[] OutputArray = null;
        List<dynamic> listListen = new List<dynamic>();
        private int _outputCount_Handle = 0;
        private int _inputCount_Handle = 0;
        private int[] _output_Handle;
        private int[] _input_Handle;
        private int _axisCount_Handle = 0;
        private int _outputsHandle;

        string outputCountHandleName = "GVL_IO.outputCount";
        string stInputHandleName = "GVL_IO.stInput";
        string stOutputHandleName = "GVL_IO.stOutput";
        string inputCountHandleName = "GVL_IO.inputCount";
        string axisCountHandleName = "GVL_Motion.MaxAxisNum";
        string axisHandleName = "GVL_Motion.Motion";
        string stOutputArrayHandleName = "GVL_IO.Outputs";

        Outputs DOs = new Outputs();
        private int[] hConnect;
        [NonSerialized]
        private AdsStream dataStream;
        [NonSerialized]
        private BinaryReader binRead;
        [NonSerialized]
        private Thread scanThread;
        [NonSerialized]
        private bool isFinalized = false;
       
           
      

        public bool CardInit(ref List<ICard> motionCards, int mode = 0)
        {
            StringBuilder netid = new StringBuilder();
            string path = Environment.CurrentDirectory + "/Config/Beckoff_NetId.ini";
            INIUtils.GetPrivateProfileString("Beckhoff", "netid", "", netid, 255, path);
            scanThread = new Thread(scanAxesStatusThread);
            scanThread.IsBackground = true; scanThread.Start();
            return CardInit(ref motionCards, netid.ToString());
        }
        public bool CardInit(int mode = 0)
        {
            StringBuilder netid = new StringBuilder();
            string path = Environment.CurrentDirectory + "/Config/Beckoff_NetId.ini";
            INIUtils.GetPrivateProfileString("Beckhoff", "netid", "", netid, 255, path);
            scanThread = new Thread(scanAxesStatusThread);
            scanThread.IsBackground = true; scanThread.Start();
            return CardInit(netid.ToString());
        }
        public bool CardInit(string netid)
        {
            bool ret = false;
            try
            {
                _client = new TcAdsClient();
                //TC2填写801,  TC3填写851  
                //_client.Connect(851);//本地模拟使用
                _client.Connect(netid, 851);//和远程的PLC通信的话需要加PLC的netid

                _outputCount_Handle = _client.CreateVariableHandle(outputCountHandleName);
                _inputCount_Handle = _client.CreateVariableHandle(inputCountHandleName);
                _axisCount_Handle = _client.CreateVariableHandle(axisCountHandleName);
                _outputsHandle = _client.CreateVariableHandle(stOutputArrayHandleName);
                _inputCount = (int)_client.ReadAny(_inputCount_Handle, typeof(int));
                _outputCount = (int)_client.ReadAny(_outputCount_Handle, typeof(int));
                _totalAxis = (int)_client.ReadAny(_axisCount_Handle, typeof(int));
                _AxisHandle = _client.CreateVariableHandle(axisHandleName);
                //_Axes = (Axes)_client.ReadAny(_AxisHandle, typeof(Axes));
                DOs = (Outputs)_client.ReadAny(_outputsHandle, typeof(Outputs));

                dataStream = new AdsStream(500);
                //Encoding is set to ASCII, to read strings
                binRead = new BinaryReader(dataStream, Encoding.ASCII);
                hConnect = new int[500];
                //添加输入监控

                _input_Handle = new int[_inputCount];
                for (int i = 0; i < _inputCount; i++)
                {
                    _input_Handle[i] = _client.CreateVariableHandle(stInputHandleName + ".I" + i);
                }
                //添加输出监控
                _output_Handle = new int[_outputCount];
                for (int i = 0; i < _outputCount; i++)
                {
                    _output_Handle[i] = _client.CreateVariableHandle(stOutputHandleName + ".Q" + i);
                }
                //添加轴监控
                _notificationAxisHandle = _client.AddDeviceNotificationEx(axisHandleName, AdsTransMode.OnChange, 1, 0, this, typeof(ST_Motion));

                _AxisHandle = _client.CreateVariableHandle(axisHandleName);




                for (int i = 0; i < _Axes.Motion.Length; i++)
                {
                    Reset(i);
                }
                this.Initialized = true;

                ret = true;
            }
            catch (Exception ex)
            {
                throw new AxisException("Beckhoff CardInit Exception:" + ex.StackTrace);
            }
            return ret;
        }

        private void scanAxesStatusThread()
        {
            while (isFinalized==false)
            {
                if (this._initialized == true)
                {
                    ReadAxes();
                    Thread.Sleep(20);
                }
            }    
        }

        public bool CardInit(ref List<ICard> motionCards, string netid)
        {
            bool ret = false;
            try
            {
                _client = new TcAdsClient();
                //TC2填写801,  TC3填写851  
                //_client.Connect(851);//本地模拟使用
                _client.Connect(netid, 851);//和远程的PLC通信的话需要加PLC的netid

                _outputCount_Handle = _client.CreateVariableHandle(outputCountHandleName);
                _inputCount_Handle = _client.CreateVariableHandle(inputCountHandleName);
                _axisCount_Handle = _client.CreateVariableHandle(axisCountHandleName);
                _outputsHandle = _client.CreateVariableHandle(stOutputArrayHandleName);
                _inputCount = (int)_client.ReadAny(_inputCount_Handle, typeof(int));
                _outputCount = (int)_client.ReadAny(_outputCount_Handle, typeof(int));
                _totalAxis = (int)_client.ReadAny(_axisCount_Handle, typeof(int));
                _AxisHandle = _client.CreateVariableHandle(axisHandleName);
                //_Axes = (Axes)_client.ReadAny(_AxisHandle, typeof(Axes));
                DOs = (Outputs)_client.ReadAny(_outputsHandle, typeof(Outputs));

                dataStream = new AdsStream(500);
                //Encoding is set to ASCII, to read strings
                binRead = new BinaryReader(dataStream, Encoding.ASCII);
                hConnect = new int[500];
                //添加输入监控
                //InputArray = new bool[_inputCount];
                //for (int i = 0; i < _inputCount; i++)
                //{
                //    hConnect[i] = _client.AddDeviceNotification(stInputHandleName + ".I" + i, dataStream, i, 1,
                //        AdsTransMode.Cyclic, 20, 0, InputArray[i]);
                //    listListen.Add(hConnect[i]);
                //}
                _input_Handle = new int[_inputCount];
                for (int i = 0; i < _inputCount; i++)
                {
                    _input_Handle[i] = _client.CreateVariableHandle(stInputHandleName + ".I" + i);
                }
                //添加输出监控
                //OutputArray = new bool[_outputCount];
                //for (int i = 0; i < _outputCount; i++)
                //{
                //    hConnect[_inputCount + i] = _client.AddDeviceNotification(stOutputHandleName + ".Q" + i, dataStream, _inputCount + i, 1,
                //        AdsTransMode.Cyclic, 20, 0, OutputArray[i]);
                //    listListen.Add(hConnect[_inputCount + i]);
                //} 
                _output_Handle = new int[_outputCount];
                for (int i = 0; i < _outputCount; i++)
                {
                    _output_Handle[i] = _client.CreateVariableHandle(stOutputHandleName + ".Q" + i);
                }
                //添加轴监控
                _notificationAxisHandle = _client.AddDeviceNotificationEx(axisHandleName, AdsTransMode.OnChange, 1, 0, this, typeof(ST_Motion));

                //_client.AdsNotification += new AdsNotificationEventHandler(AdsNotificationEventOnChange);
                _AxisHandle = _client.CreateVariableHandle(axisHandleName);
                ReadAxes();
                for (int i = 0; i < _Axes.Motion.Length; i++)
                {
                    Reset(i);
                }



                Beckhoff card = this;
                //轴的个数，IO的个数
                card.CardID = 0;
                card.CardType = "Beckhoff";
                card.TotalAxis = _totalAxis;
                card.InputCount = _inputCount;
                card.OutputCount = _outputCount;
                card.StartAxisID = 0;
                card.Initialized = true;
                motionCards.Add(card);

                ret = true;
            }
            catch (Exception ex)
            {
                throw new AxisException("Beckhoff CardInit Exception:" + ex.StackTrace);
            }
            return ret;
        }
        public void AdsNotificationEventOnChange(object sender, AdsNotificationEventArgs e)
        {
            try
            {
                e.DataStream.Position = e.Offset;
                int index = listListen.IndexOf(e.NotificationHandle);
                if (e.NotificationHandle == _notificationAxisHandle)
                    //ReadAxes();
                    if (index < 0 || index > listListen.Count)
                    {
                        return;
                    }
                if (index < InputCount)
                {
                    InputArray[index] = binRead.ReadBoolean();
                    //UpdateUI_DI(index);
                    return;
                }
                else if (index < InputCount + OutputCount)
                {
                    OutputArray[index - InputCount] = binRead.ReadBoolean();
                    //UpdateUI_DO(index - InputCount);
                    return;
                }
            }
            catch (Exception ex)
            {

                throw;
            }

        }
        public bool Reset(int axisId)
        {
            lock (this)
            {
                if (axisId < 0 || axisId > _totalAxis)
                {
                    throw new BZ.Core.IOException("Beckhoff Reset out of range!");
                }
                try
                {
                    CloseCmd(axisId);

                    _Axes.Motion[axisId].MoitonCmd.bReset = true;
                    WriteAny(_AxisHandle, _Axes);
                    Thread.Sleep(20);
                    _Axes.Motion[axisId].MoitonCmd.bReset = false;
                    WriteAny(_AxisHandle, _Axes);
                }
                catch (Exception ex)
                {
                    throw ex;
                }

                return true;
            }
        }

        public bool GetDI(int card, int port = 0)
        {
            if (port < 0 || port > _inputCount)
            {
                throw new BZ.Core.IOException("Beckhoff GetDI out of range!");
            }
            //bool val = InputArray[port];
            var val = (int)_client.ReadAny(_input_Handle[port], typeof(int));
            if (val == 1)
            {
                return true;
            }
            return false;
        }

        public bool GetDO(int card, int port = 0)
        {
            if (port < 0 || port > _inputCount)
            {
                throw new BZ.Core.IOException("Beckhoff GetDO out of range!");
            }
            //bool val = OutputArray[port];
            //return val;
            var val = (int)_client.ReadAny(_output_Handle[port], typeof(int));
            if (val == 1)
            {
                return true;
            }
            return false;
        }

        public bool SetDO(int mod, int port, int value)
        {
            try
            {
                lock (this)
                {
                    DOs = (Outputs)_client.ReadAny(_outputsHandle, typeof(Outputs));
                    DOs.Output[port] = (byte)value;
                    WriteAny(_outputsHandle, DOs);
                }
            }
            catch (Exception ex)
            {
                return false;
            }
            return true;
        }

        public bool CheckMoveDone(short axisId)
        {
            //lock (this)
            {
                //ReadAxes();
                if (_Axes.Motion.Length < axisId)
                {
                    throw new AxisException("Get Move Done Status Exception: axisId is out of range!");
                }
                try
                {
                    return !_Axes.Motion[axisId].MotionStatus.bMoving;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        public bool Finalize()
        {
            try
            {
                _client?.DeleteVariableHandle(_AxisHandle);
                _client?.Disconnect();
                _client?.Dispose();
                isFinalized = true;
                scanThread?.Abort();
            }
            catch
            {
                return false;
            }
            return true;
        }

        public bool GetORGStatus(short axisId)
        {
            //ReadAxes();
            if (_Axes.Motion.Length < axisId)
            {
                throw new AxisException("Get ORG Status Exception: axisId is out of range!");
            }
            try
            {
                return _Axes.Motion[axisId].MotionStatus.bORG;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool GetMELStatus(short axisId)
        {
            //ReadAxes();
            if (_Axes.Motion.Length < axisId)
            {
                throw new AxisException("Get MEL Status Exception: axisId is out of range!");
            }
            try
            {
                return _Axes.Motion[axisId].MotionStatus.bMEL;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool GetPELStatus(short axisId)
        {
            //ReadAxes();
            if (_Axes.Motion.Length < axisId)
            {
                throw new AxisException("Get PEL Status Exception: axisId is out of range!");
            }
            try
            {
                return _Axes.Motion[axisId].MotionStatus.bPEL;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool GetINPStatus(short axisId)
        {
            //ReadAxes();
            if (_Axes.Motion.Length < axisId)
            {
                throw new AxisException("Get Move Done Status Exception: axisId is out of range!");
            }
            try
            {
                return _Axes.Motion[axisId].MotionStatus.bINP;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool GetEMGStatus(short axisId)
        {
            //ReadAxes();
            if (_Axes.Motion.Length < axisId)
            {
                throw new AxisException("Get EMG Status Exception: axisId is out of range!");
            }
            try
            {
                if (_Axes.Motion[axisId].MotionStatus.bEMG)
                {
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool GetALMStatus(short axisId)
        {
            //lock (this)
            {
               // ReadAxes();//xxl

                try
                {

                    if (_Axes.Motion[axisId].MotionStatus.bALM)
                    {
                        return true;
                    }
                    return false;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        public bool GetASTPStatus(short axisId)
        {
            throw new NotImplementedException();
        }

        public bool GetCSTPStatus(short axisId)
        {
            throw new NotImplementedException();
        }

        public bool GetNSTPStatus(short axisId)
        {
            return !IsMoving(axisId);
        }

        public bool GetHMVStatus(short axisId)
        {
           // ReadAxes();//xxl
            if (_Axes.Motion.Length < axisId)
            {
                throw new AxisException("Get HMV Status Exception: axisId is out of range!");
            }
            try
            {
                if (_Axes.Motion[axisId].MotionStatus.bHoming)
                {
                    return true;
                }
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool SetPos(int axisId, double pos)
        {
            try
            {
                lock (this)
                {
                    CloseCmd(axisId);

                    _Axes.Motion[axisId].MoitonCmd.rSetPositon = pos;
                    _Axes.Motion[axisId].MoitonCmd.bSetPostion = true;
                    WriteAny(_AxisHandle, _Axes);
                }
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool GetServoOnStatus(short axisId)
        {
            // ReadAxes();//xxl

            if (_Axes.Motion.Length < axisId)
            {
                throw new AxisException("Get ServoOn Status Exception: axisId is out of range!");
            }
            try
            {
                return _Axes.Motion[axisId].MotionStatus.bServoStatus;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool GetAxisAlarmStatus(short axisId)
        {
            return GetALMStatus(axisId);
        }

        public bool GetAxisMelStatus(short axisId)
        {
            return GetMELStatus(axisId);
        }

        public bool GetAxisPelStatus(short axisId)
        {
            return GetPELStatus(axisId);
        }

        public bool GetCmdPosition(short axisId, ref double commandPosition)
        {
            throw new NotImplementedException();
        }

        public bool GetEmgStatus(short axisId)
        {
            throw new NotImplementedException();
        }

        public bool GetErrorPosition(short axisId, ref double errorPosition)
        {
            // ReadAxes();//xxl

            if (_Axes.Motion.Length < axisId)
            {
                throw new AxisException("Get ServoOn Status Exception: axisId is out of range!");
            }
            try
            {
                errorPosition = _Axes.Motion[axisId].MotionStatus.rErrPos;
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool GetFeedbackPosition(short axisId, ref double feedbackPosition)
        {
            // ReadAxes();//xxl

            if (_Axes.Motion.Length < axisId)
            {
                throw new AxisException("Get ServoOn Status Exception: axisId is out of range!");
            }
            try
            {
                feedbackPosition = _Axes.Motion[axisId].MotionStatus.rActPos;
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool GetFeedbackVelocity(short axisId, ref double feedbackVelocity)
        {
            throw new NotImplementedException();
        }

        public bool GetMotionIoSatus(short axisId, int motionIoStatusBit)
        {
            int? status = null;
            try
            {
                if (motionIoStatusBit == 1)
                {
                    return GetPELStatus((short)axisId);
                }
                if (motionIoStatusBit == 2)
                {
                    return GetMELStatus((short)axisId);
                }
                if (motionIoStatusBit == 3)
                {
                    return GetORGStatus((short)axisId);
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetMotionStatus Exception! " + ex.StackTrace);
            }
            return false;
        }

        public bool GetMotionStatus(short axisId, int motionStatusBit)
        {
            throw new NotImplementedException();
        }

        public bool GetTargetPosition(short axisId, ref double targetPosition)
        {
            throw new NotImplementedException();
        }

        public bool HomeMove(short axisId, PRA_HOME_ENUM homeMode, DIR_ENUM homeDir, PRA_SF_ENUM homeCure, double homeAcc, double homeVm, double homeVo, double homeShiftDistance)
        {
            lock (this)
            {
                // ReadAxes();//xxl

                if (_Axes.Motion.Length < axisId)
                {
                    throw new AxisException("HomeMove Exception: axisId is out of range!");
                }
                try
                {
                    CloseCmd(axisId);

                    if (homeMode == PRA_HOME_ENUM.HOME_MODE_ORG)
                    {
                        _Axes.Motion[axisId].MoitonCmd.bHomeMode = 0;
                    }
                    else
                    {
                        _Axes.Motion[axisId].MoitonCmd.bHomeMode = 1;
                    }
                    if (homeDir == DIR_ENUM.Positive)
                    {
                        _Axes.Motion[axisId].MoitonCmd.bHomeSearchDir = 1;
                    }
                    else
                    {
                        _Axes.Motion[axisId].MoitonCmd.bHomeSearchDir = 3;
                    }
                    _Axes.Motion[axisId].MoitonCmd.rAcc = homeAcc;
                    _Axes.Motion[axisId].MoitonCmd.rDec = homeAcc;
                    _Axes.Motion[axisId].MoitonCmd.rSetVelo = homeVm;
                    _Axes.Motion[axisId].MoitonCmd.rHomeShift = homeShiftDistance;
                    _Axes.Motion[axisId].MoitonCmd.bHome = true;
                    WriteAny(_AxisHandle, _Axes);
                    Stopwatch sw = new Stopwatch();
                    sw.Restart();
                    while (!IsMoving(axisId))
                    {
                        Thread.Sleep(10);
                        if (sw.ElapsedMilliseconds > 10000)
                        {
                            return false;
                        }
                    }
                }

                catch (Exception ex)
                {
                    throw ex;
                }
            }
            return true;
        }

        public bool InterPolationLine(int[] axisIdArray, double[] axisPosArray, PRA_OPTION_ENUM apsOption, double vm, double acc = 0.1, double dec = 0.1, PRA_SF_ENUM SF = PRA_SF_ENUM.S_CURVE)
        {
            int? ret = 0;
            double[] positionArray = new double[10];
            double[] Vm = new double[10];
            double[] Acc = new double[10];
            double[] Dec = new double[10];
            try
            {
                if (axisIdArray.Length == axisPosArray.Length)
                {
                    for (int axisNumIndex = 0; axisNumIndex < axisPosArray.Length; axisNumIndex++)
                    {
                        Vm[axisNumIndex] = vm;
                        Acc[axisNumIndex] = acc;
                        Dec[axisNumIndex] = dec;
                        positionArray[axisNumIndex] = axisPosArray[axisNumIndex];
                        PTPMove((short)axisIdArray[axisNumIndex], apsOption, Vm[axisNumIndex], Acc[axisNumIndex], Dec[axisNumIndex], positionArray[axisNumIndex]);

                    }
                    if (ret != 0)
                    {
                        //m_Logger.Error("轴" + axisIdArray[axisNumIndex] + "InterPolationLine失败！");
                        //return false;
                    }
                }
            }
            catch (Exception ex)
            {
                //m_Logger.Error("多轴直线插补运动失败！" + ex.StackTrace);
                return false;
            }
            return true;
        }

        public bool IsMoving(int axisId)
        {
            // ReadAxes();//xxl

            if (_Axes.Motion.Length < axisId)
            {
                throw new AxisException("Get Move Done Status Exception: axisId is out of range!");
            }
            try
            {
                return _Axes.Motion[axisId].MotionStatus.bMoving;

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool LoadParamFile(string filePath, int boardId)
        {
            throw new NotImplementedException();
        }

        public bool MoveVel(short axisId, DIR_ENUM dir, double acc, double dec, double vm, double SF = 0.5)
        {
            try
            {
                lock (this)
                {

                    if (dir == DIR_ENUM.Negative)
                    {
                        _Axes.Motion[axisId].MoitonCmd.bDir = 3;
                    }
                    else
                    {
                        _Axes.Motion[axisId].MoitonCmd.bDir = 1;
                    }
                    _Axes.Motion[axisId].MoitonCmd.rAcc = acc;
                    _Axes.Motion[axisId].MoitonCmd.rDec = dec;
                    _Axes.Motion[axisId].MoitonCmd.rSetVelo = vm;
                    _Axes.Motion[axisId].MoitonCmd.bMoveVeloStart = true;
                    WriteAny(_AxisHandle, _Axes);
                }
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void P2PMoveWait(int[] axisIdArray, double[] axisPosArray, PRA_OPTION_ENUM apsOption, double[] vm, double[] acc, double[] dec)
        {
            throw new NotImplementedException();
        }

        public void PointTableMove(int _cardId, int axis0, int axis1, double[] x, double[] y, double vm, double acc)
        {
            throw new NotImplementedException();
        }

        public bool PTPMove(short axisId, PRA_OPTION_ENUM ApsOption, double vm, double acc, double dec, double position)
        {
            try
            {
                lock (this)
                {
                    CloseCmd(axisId);

                    _Axes.Motion[axisId].MoitonCmd.rAcc = acc;
                    _Axes.Motion[axisId].MoitonCmd.rDec = dec;
                    _Axes.Motion[axisId].MoitonCmd.rSetVelo = vm;
                    if (ApsOption == PRA_OPTION_ENUM.Absolute)
                    {
                        _Axes.Motion[axisId].MoitonCmd.rMoveAbsSetPos = position;
                        _Axes.Motion[axisId].MoitonCmd.bMoveAbsStart = true;
                    }
                    else
                    {
                        _Axes.Motion[axisId].MoitonCmd.rMoveRelativeSetPos = position;
                        _Axes.Motion[axisId].MoitonCmd.bMoveRelativeStart = true;
                    }
                    WriteAny(_AxisHandle, _Axes);
                    Thread.Sleep(100);
                }
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool JogMoveStart(short axisId, DIR_ENUM apsOption, double jogVm, double jogAcc)
        {
            try
            {
                lock (this)
                {
                    CloseCmd(axisId);

                    _Axes.Motion[axisId].MoitonCmd.rAcc = jogAcc;
                    _Axes.Motion[axisId].MoitonCmd.rDec = jogAcc;
                    _Axes.Motion[axisId].MoitonCmd.rSetVelo = jogVm;
                    if (apsOption == DIR_ENUM.Negative)
                    {
                        _Axes.Motion[axisId].MoitonCmd.bJogN = true;
                    }
                    else
                    {
                        _Axes.Motion[axisId].MoitonCmd.bJogP = true;
                    }
                    WriteAny(_AxisHandle, _Axes);
                }
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool JogMoveStop(short axisId)
        {
            try
            {
                CloseCmd(axisId);
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool ServoOff(int axisId)
        {
            try
            {
                lock (this)
                {
                    CloseCmd(axisId);

                    _Axes.Motion[axisId].MoitonCmd.bEnable = false;
                    WriteAny(_AxisHandle, _Axes);
                }
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool ServoON(int axisId)
        {
            try
            {
                lock (this)
                {
                    CloseCmd(axisId);

                    _Axes.Motion[axisId].MoitonCmd.bEnable = true;
                    WriteAny(_AxisHandle, _Axes);
                }
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool StopEmg(short axisId)
        {
            try
            {
                lock (this)
                {
                    CloseCmd(axisId);

                    _Axes.Motion[axisId].MoitonCmd.bStop = true;
                    WriteAny(_AxisHandle, _Axes);
                }
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool StopMove(short axisId, double acc)
        {
            try
            {
                lock (this)
                {
                    CloseCmd(axisId);

                    _Axes.Motion[axisId].MoitonCmd.bStop = true;
                    WriteAny(_AxisHandle, _Axes);
                }
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void TriggleZeroCount(int board, int[] channel, int num)
        {
            throw new NotImplementedException();
        }

        public void TwoDtrigger(int _cardId, int TGR_SRC, int axis0, int axis1, double[] x, double[] y, int windows, int width)
        {
            throw new NotImplementedException();
        }

        private void CloseCmd(int axisId)
        {
            // ReadAxes();//xxl

            _Axes.Motion[axisId].MoitonCmd.bHome = false;
            _Axes.Motion[axisId].MoitonCmd.bHalt = false;
            _Axes.Motion[axisId].MoitonCmd.bMoveAbsStart = false;
            _Axes.Motion[axisId].MoitonCmd.bMoveRelativeStart = false;
            _Axes.Motion[axisId].MoitonCmd.bMoveVeloStart = false;
            _Axes.Motion[axisId].MoitonCmd.bJogP = false;
            _Axes.Motion[axisId].MoitonCmd.bJogN = false;
            _Axes.Motion[axisId].MoitonCmd.bStop = false;
            _Axes.Motion[axisId].MoitonCmd.bSetPostion = false;
            WriteAny(_AxisHandle, _Axes);
            Thread.Sleep(50);
        }






        private void WriteAny(int handle, object obj)
        {
            lock (this)
            {
                try
                {
                    _client.WriteAny(handle, obj);
                }
                catch (Exception ex)
                {


                }

            }
        }
        private void ReadAxes()
        {
            //lock (this)
            {
                try
                {
                    _Axes = (Axes)_client.ReadAny(_AxisHandle, typeof(Axes));
                }

                catch (Exception ex)
                {

                }
            }
        }

        public bool HomeMove(short axisId, PRA_HOME_ENUM homeMode, DIR_ENUM homeDir, PRA_SF_ENUM homeCure, double homeAcc, double homeVm, double homeVo, double homeShiftDistance, double stopDec, SWITCH_ENUM isEnableSoftLimit, double spelPos, double smelPos)
        {
            return HomeMove(axisId, homeMode, homeDir, homeCure, homeAcc, homeVm, homeVo, homeShiftDistance);
        }

        public bool StartGear(short axisId, GEAR_MODE mode)
        {
            throw new NotImplementedException();
        }

        public bool IsHoming(int axisID)
        {
            return IsMoving(axisID);
        }

        public bool ClearAlarm(short axisId)
        {
            return Reset(axisId);
        }

        public void UpdateSlaveResource(ref ICard card, int mode = 0)
        {
            throw new NotImplementedException();
        }
    }
}
